
package com.wwy.monitor.service.impl;

import com.ali.com.google.common.base.Joiner;
import com.wwy.monitor.common.DingGroupMsgContext;
import com.wwy.monitor.common.MessageException;
import com.wwy.monitor.common.PageResult;
import com.wwy.monitor.executor.MonitorExecutor;
import com.wwy.monitor.mapper.tddl.*;
import com.wwy.monitor.model.enumeration.DingBodyTypeEnum;
import com.wwy.monitor.model.enumeration.MonitorEnvEnum;
import com.wwy.monitor.model.enumeration.MonitorTypeEnum;
import com.wwy.monitor.model.tddl.dto.MonitorAppDTO;
import com.wwy.monitor.model.tddl.dto.MonitorConfigDetailDTO;
import com.wwy.monitor.model.tddl.dto.MonitorIpDTO;
import com.wwy.monitor.model.tddl.dto.MonitorLogDTO;
import com.wwy.monitor.model.tddl.dto.MonitorReceiverDTO;
import com.wwy.monitor.model.tddl.dto.MonitorTaskDTO;
import com.wwy.monitor.model.tddl.query.MonitorConfigDetailQuery;
import com.wwy.monitor.model.tddl.query.MonitorTaskQuery;
import com.wwy.monitor.model.tddl.vo.MonitorConfigDetailVo;
import com.wwy.monitor.model.tddl.vo.MonitorLogVO;
import com.wwy.monitor.model.tddl.vo.MonitorTaskVo;
import com.wwy.monitor.model.vo.DingMessageVO;
import com.wwy.monitor.model.vo.OaBody;
import com.wwy.monitor.service.McFactory;
import com.wwy.monitor.service.MonitorIpService;
import com.wwy.monitor.service.MonitorTaskService;
import com.wwy.monitor.service.NoticeService;
import com.wwy.monitor.util.DateUtil;
import com.wwy.monitor.util.MailUtils;
import com.autonavi.acis.system.service.DingTalkService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.taobao.tddl.client.sequence.impl.GroupSequence;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

/**
 * @author long.Wanheng
 * @version V1.00
 * @createDate 2019/10/30
 */
@Service(value = "monitorTaskService")
public class MonitorTaskServiceImpl implements MonitorTaskService {
    static final Logger logger = LoggerFactory.getLogger(MonitorTaskServiceImpl.class);
    @Autowired
    private MonitorTaskMapper monitorTaskMapper;
    @Autowired
    private MonitorConfigDetailMapper monitorConfigDetailMapper;
    @Autowired
    private MonitorIpMapper monitorIpMapper;
    @Autowired
    private MonitorReceiverMapper monitorReceiverMapper;
    @Autowired
    private MonitorLogMapper monitorLogMapper;
    @Autowired
    private NoticeService noticeService;
    @Autowired
    private MonitorAppMapper monitorAppMapper;
    @Autowired
    private DingTalkService dingTalkService;
    @Autowired
    private MonitorIpService monitorIpService;
    @Resource(name = "monitorLogSequence")
    private GroupSequence groupSequence;
    @Value("${system.domain.url}")
    private String domainUrl;
    @Value("${server.port}")
    private Integer port;
    @Value("${system.server.protocol}")
    private String protocol;
    @Value("${server.env}")
    private String env;
    public static String serverIp = "";

    @Override
    public PageResult queryMonitorTask(MonitorTaskQuery query) {
        getIntListStatus(query);
        if (query.getStartTime() != null && query.getEndTime() != null) {
            query.setStartDate(new Date(query.getStartTime()));
            query.setEndDate(new Date(query.getEndTime()));
        }
        int pageNum = query.getPageNum();
        int pageSize = query.getPageSize();
        Integer offset = (pageNum - 1) * pageSize;
        query.setPageNum(offset);
        query.setPageSize(pageSize);
        int dataCount = monitorTaskMapper.queryMonitorTaskCount(query);
        int pages = (dataCount + pageSize - 1) / pageSize;
        List<MonitorTaskDTO> data = monitorTaskMapper.queryMonitorTask(query);
        PageResult result = new PageResult();
        result.setCurrentPage(pageNum);
        result.setPages(pages);
        result.setPageSize(pageSize);
        result.setTotalCount(dataCount);
        result.setDatas(data);
        return result;
    }

    private void getIntListStatus(MonitorTaskQuery query) {
        if (StringUtils.isBlank(query.getStatusStr())) {
            return;
        }
        String[] strings = query.getStatusStr().split(",");
        List<Integer> list = Lists.newArrayList();
        try {
            for (String str : strings) {
                list.add(Integer.parseInt(str));
            }
            query.setStatusInList(list);
        } catch (Exception e) {
            throw new MessageException("éæ³ç¶æ");
        }
    }

    @Override
    public int stopTaskByAppId(Long appId) {
        return monitorTaskMapper.stopTaskByAppId(appId);
    }

    @Override
    public void saveTaskByMonitorCongfigDetail(MonitorConfigDetailQuery query) {
//æ¥è¯¢çæ§éç½®è§åè¡¨
        List<MonitorTaskDTO> saveTaskList = Lists.newArrayList();
        List<MonitorConfigDetailVo> updateList = Lists.newArrayList();
        List<MonitorConfigDetailVo> configDetailVos = monitorConfigDetailMapper.findAllByConfigQuery(query);
//å¤æ­å½åçæ§æ¶é´ - ä¸æ¬¡çæ§æ¶é´ ä¸çæ§é¢æ¬¡åæ¯è¾
        if (configDetailVos != null && configDetailVos.size() > 0) {
            for (MonitorConfigDetailVo vo : configDetailVos) {
                if (vo.getMonitorTime() == null || DateUtil.getMinuteByDate(query.getTaskTime(), vo.getMonitorTime()) >= vo.getRate()) {
                    MonitorTaskDTO dto = new MonitorTaskDTO();
                    dto.setAppId(vo.getAppId());
                    dto.setDetailId(vo.getId());
                    dto.setTaskName(vo.getAppName() + "_" + vo.getConfigName() + "_" + DateUtil
                            .format(query.getTaskTime(), DateUtil.DEFAULT_PATTERN));
                    dto.setStatus(0);
                    dto.setConfigType(vo.getConfigType());
                    dto.setCreateUser("system");
                    saveTaskList.add(dto);
//æ´æ°çæ§æ¶é´
                    if (vo.getMonitorTime() == null) {
                        vo.setMonitorTime(query.getTaskTime());
                    } else {
                        vo.setMonitorTime(DateUtil.incrMinAndGet(vo.getMonitorTime(), vo.getRate()));
                    }
                    updateList.add(vo);
                }
            }
        }
        if (updateList.size() > 0) {
            monitorConfigDetailMapper.updateBatchMonitorTime(updateList);
        }
        if (saveTaskList.size() > 0) {
            monitorTaskMapper.addBatchMonitorTask(saveTaskList);
        }
    }

    @Override
    public void dealMonitorTaskAndSendMsg(Integer type) {
        if (env.contains("publish") || env.contains("daily") || env.contains("local")) {
            try {
                InetAddress address = InetAddress.getLocalHost();
                if ("".equals(serverIp)) {
                    serverIp = address.getHostAddress();
                }
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            boolean retryFlag = true;
//æ ¹æ®ç±»åæ¥è¯¢ææä»»å¡
            while (retryFlag) {
                MonitorTaskVo taskVo = monitorTaskMapper.queryMonitorTaskByType(type);
//å¦æè·åå°æªæ§è¡çä»»å¡æ°æ®
                if (taskVo != null) {
                    MonitorTaskVo monitorTaskVo = new MonitorTaskVo();
                    monitorTaskVo.setId(taskVo.getId());
                    monitorTaskVo.setUpdateTime(new Date());
                    monitorTaskVo.setUpdateUser("system-" + env);
                    monitorTaskVo.setServerIp(serverIp);
                    try {
//å°æ¥è¯¢åºæ¥çä»»å¡ç«å»æ´æ°æä»»å¡æ§è¡ä¸­
                        monitorTaskVo.setStatus(0);
                        monitorTaskVo.setChangeStatus(1);
                        int count = monitorTaskMapper.updateTaskStatusById(monitorTaskVo);
                        if (count > 0) {
//æ¥è¯¢monitor_app å monitor_config_detail
                            MonitorAppDTO appDTO = monitorAppMapper.selectById(taskVo.getAppId());
                            if (appDTO != null) {
                                taskVo.setAppName(appDTO.getAppName());
                                taskVo.setDomainUrl(appDTO.getDomainUrl());
                            }
                            MonitorConfigDetailDTO configDetailDTO = monitorConfigDetailMapper.selectById(taskVo.getDetailId());
                            if (configDetailDTO != null) {
                                taskVo.setConfigId(configDetailDTO.getConfigId());
                                taskVo.setUrl(configDetailDTO.getUrl());
                                taskVo.setParam(configDetailDTO.getParam());
                                taskVo.setComparator(configDetailDTO.getComparator());
                                taskVo.setExceptResult(configDetailDTO.getExcept());
                                taskVo.setRequestMethod(configDetailDTO.getRequestMethod());
                                taskVo.setRequestHeader(configDetailDTO.getRequestHeader());
                                taskVo.setAlertDelayTime(configDetailDTO.getAlertDelayTime());
                                taskVo.setMonitorType(configDetailDTO.getMonitorType());
                                taskVo.setContentType(configDetailDTO.getContentType());
                            }
                            taskVo.setPort(port);
                            taskVo.setProtocol(protocol);
                            Date ds = DateUtil.formateDateString(
                                    DateUtil.format(taskVo.getCreateTime(), DateUtil.SHOW_PATTERN_DATE),
                                    DateUtil.SHOW_PATTERN_DATE);
//APPåéç½®è¯¦æä¿¡æ¯é½æ¥å°ææ§è¡ä»»å¡ï¼å¦åè®¤ä¸ºéç½®ç¼ºå¤±
                            if (appDTO != null && configDetailDTO != null) {
//è·ååºç¨æºå¨åè¡¨
                                List<MonitorIpDTO> ipList = Lists.newArrayList();
//å¤æ­æ¯åæºè¿æ¯å¤æº 0å¤æº 1åæº
                                if (taskVo.getMonitorType() == 0) {
                                    ipList = monitorIpMapper.selectByAppIds(Lists.newArrayList(taskVo.getAppId()), 0,
                                            MonitorEnvEnum.parseStatus(env));
                                } else {
                                    if (StringUtils.isNotEmpty(taskVo.getDomainUrl())) {
                                        MonitorIpDTO ipDTO = new MonitorIpDTO();
                                        ipDTO.setIp(taskVo.getDomainUrl());
                                        ipList.add(ipDTO);
                                    } else {
                                        List<MonitorIpDTO> ips = monitorIpMapper.selectByAppIds(Lists.newArrayList(taskVo.getAppId()), 0,
                                                MonitorEnvEnum.parseStatus(env));
                                        if (ips != null && ips.size() > 0) {
                                            ipList.add(ipList.get(0));
                                        }
                                    }
                                }
                                if (ipList != null && ipList.size() > 0) {
                                    taskVo.setIpList(ipList.stream().map(MonitorIpDTO::getIp).collect(Collectors.toList()));
//è·åéç¥äººåè¡¨
                                    List<MonitorReceiverDTO> receiverDTOS = monitorReceiverMapper.selectByDetailIds(
                                            Lists.newArrayList(taskVo.getDetailId()));
//å¾ªç¯å¤çä»»å¡ï¼è°ç¨çæ§æ¥å£
                                    List<Map<String, Object>> resultList = MonitorExecutor.getResultByMonitorTask(taskVo);
                                    if (resultList != null && resultList.size() > 0) {
                                        monitorTaskVo.setIpSize(resultList.size());
                                        List<MonitorLogVO> logDTOS = Lists.newArrayList();
                                        Integer successCount = 0;
                                        Integer failCount = 0;
//ä¿å­æ¯å°æºå¨ççæ§è®°å½monitor_log
                                        for (Map<String, Object> map : resultList) {
                                            MonitorLogVO dto = new MonitorLogVO();
                                            dto.setId(groupSequence.nextValue());
                                            dto.setAppId(taskVo.getAppId());
                                            dto.setAppName(taskVo.getAppName());
                                            dto.setConfigId(taskVo.getConfigId());
                                            dto.setConfigName(MonitorTypeEnum.parseDesc(taskVo.getConfigType()));
                                            dto.setConfigType(taskVo.getConfigType());
                                            dto.setDetailId(taskVo.getDetailId());
                                            dto.setTaskId(taskVo.getId());
                                            dto.setTaskName(taskVo.getTaskName());
                                            dto.setIp(map.get("ip").toString());
                                            dto.setUrl(taskVo.getUrl());
                                            dto.setParam(taskVo.getParam());
                                            dto.setComparator(taskVo.getComparator());
                                            dto.setExcept(taskVo.getExceptResult());
                                            dto.setRequestMethod(taskVo.getRequestMethod());
                                            dto.setRequestHeader(taskVo.getRequestHeader());
                                            dto.setResponse(map.get("response").toString());
                                            dto.setResult((Integer) map.get("result"));
                                            if ((Integer) map.get("result") == 0) {
                                                dto.setResultDesc("å¤±è´¥");
                                                failCount++;
                                            } else {
                                                successCount++;
                                                dto.setResultDesc("æå");
                                            }
                                            dto.setCreateTime(new Date());
                                            dto.setDs(ds);
                                            logDTOS.add(dto);
                                        }
                                        monitorTaskVo.setSuccessCount(successCount);
                                        monitorTaskVo.setFailCount(failCount);
                                        Map<String, List<MonitorLogDTO>> logMap = Maps.newConcurrentMap();
                                        if (logDTOS.size() > 0) {
                                            logMap = logDTOS.stream().collect(
                                                    Collectors.groupingBy(MonitorLogDTO::getResponse));
                                            monitorLogMapper.batchInsertMonitorLog(logDTOS);
                                            monitorTaskVo.setResultList(logDTOS);
                                        }
//æ´æ°ç¶æä¸ºä»»å¡å·²å®æ
                                        monitorTaskVo.setUpdateTime(new Date());
                                        monitorTaskVo.setStatus(1);
                                        monitorTaskVo.setChangeStatus(2);
                                        int updateCount = monitorTaskMapper.updateTaskStatusById(monitorTaskVo);
                                        boolean sendMsg = isSendMsg(new Date(), taskVo);
//æ¯å¦åéééãé®ä»¶æ¶æ¯æé
                                        if (sendMsg) {
//å·²æ´æ°ç¶æï¼å¹¶ä¸æçæ§å¤±è´¥çæºå¨ï¼ååé®ä»¶éç¥
                                            if (updateCount > 0 && (failCount > 0 || logMap.size() > 1)) {
//è°ç¨æå¡åæ­¥serverIpæ¹æ³
                                                try {
                                                    monitorIpService.syncServerIp(taskVo.getAppName());
                                                } catch (Exception e) {
                                                    logger.info("sync server ip fail {}", e.getMessage());
                                                }
                                                if (receiverDTOS != null && receiverDTOS.size() > 0) {
                                                    List<String> sendEmailList = Lists.newArrayList();
                                                    List<String> empIds = Lists.newArrayList();
                                                    List<String> tokens = Lists.newArrayList();
                                                    for (MonitorReceiverDTO receiverDTO : receiverDTOS) {
                                                        if (receiverDTO.getAlertType() == 0) {
                                                            if (receiverDTO.getAddress() != null && !sendEmailList.contains(
                                                                    receiverDTO.getAddress())) {
                                                                sendEmailList.add(
                                                                        MailUtils.replaceEmailAddress(receiverDTO.getAddress()));
                                                            }
                                                            if (receiverDTO.getType() == 0 && !empIds.contains(
                                                                    receiverDTO.getEmpId())) {
                                                                empIds.add(receiverDTO.getEmpId());
                                                            }
                                                        } else if (receiverDTO.getAlertType() == 1) {
                                                            if (receiverDTO.getAddress() != null && !tokens.contains(
                                                                    receiverDTO.getAddress())) {
                                                                tokens.add(receiverDTO.getAddress());
                                                            }
                                                        }
                                                    }
//åééééç¥
                                                    if (empIds.size() > 0) {
                                                        sendDingMsg(empIds, taskVo);
                                                    }
//åééç¾¤éç¥
                                                    if (tokens.size() > 0) {
                                                        sendDingGroupMsg(tokens, taskVo);
                                                    }
//åéé®ä»¶éç¥
                                                    if (sendEmailList.size() > 0) {
                                                        String emailTitle = taskVo.getTaskName();
                                                        if (!"http://abs-monitor.amap.com".equals(domainUrl)) {
                                                            emailTitle = "(æµè¯é®ä»¶)" + emailTitle;
                                                        }
                                                        Map<String, Object> parameters = new HashMap<>(16);
                                                        parameters.put("monitor", monitorTaskVo);
                                                        parameters.put("title", emailTitle);
                                                        boolean result = noticeService.sendNotifyEmail("monitorEmail", parameters,
                                                                sendEmailList);
                                                        if (result) {
                                                            logger.info("Send monitor mail success [{}] to {}", emailTitle,
                                                                    Joiner.on(",").join(sendEmailList));
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                } else {
//æ æå¡ipæ´æ°ç¶æä¸ºä»»å¡å·²å®æ
                                    monitorTaskVo.setUpdateTime(new Date());
                                    monitorTaskVo.setStatus(1);
                                    monitorTaskVo.setChangeStatus(2);
                                    monitorTaskMapper.updateTaskStatusById(monitorTaskVo);
                                }
                            } else {
//æ æå¡ipæ´æ°ç¶æä¸ºä»»å¡å·²å®æ
                                monitorTaskVo.setUpdateTime(new Date());
                                monitorTaskVo.setStatus(1);
                                monitorTaskVo.setChangeStatus(3);
                                monitorTaskMapper.updateTaskStatusById(monitorTaskVo);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
//å¦ææ¯ä»»å¡å¨æ§è¡ä¸­åºå¼å¸¸ï¼åå°ä»»å¡è¿åç¶æè³æªæ§è¡ç¶æ
                        if (monitorTaskVo.getStatus() == 1) {
                            monitorTaskVo.setStatus(1);
                            monitorTaskVo.setChangeStatus(0);
                            monitorTaskMapper.updateTaskStatusById(monitorTaskVo);
                        }
                    }
                } else {
//æ¥è¯¢æ¯å¦è¿æå¾å¤ççä»»å¡
                    if (monitorTaskMapper.queryMonitorCountTaskByType(type) == 0) {
                        retryFlag = false;
//logger.info("[{}]æ²¡æå¾æ§è¡ççæ§ä»»å¡", MonitorTypeEnum.parseDesc(type));}
                    }
                }
            }
        }
/**
 * åéééå·¥ä½éç¥
 * @param empIds
 * @param taskVo
 */
        public void sendDingMsg (List < String > empIds, MonitorTaskVo taskVo){
//ééå·¥ä½éç¥æé
            for (String empId : empIds) {
                DingMessageVO msg = new DingMessageVO();
                msg.setType(DingBodyTypeEnum.OA.getType());
                OaBody oaBody = new OaBody();
                oaBody.setBodyTitle("åºç¡æ¯æ-çæ§å¹³å°æ¶æ¯éç¥");
                StringBuilder content = new StringBuilder();
                content.append(taskVo.getTaskName() + "çæ§ç»æä¸é¢æä¸ä¸è´ï¼");
                content.append("\n");
                content.append("çæ§ä»»å¡æ§è¡æ¶é´: " + DateUtil.format(taskVo.getCreateTime(), DateUtil.SHOW_PATTERN_HMS));
                content.append("\n");
                content.append("æ¶æ¯åéæ¶é´: " + DateUtil.format(LocalDateTime.now(), DateUtil.SHOW_PATTERN_HMS_SSS));
                content.append("\n");
                content.append("å·ä½ä¿¡æ¯è¯·ç»å½ãåºç¡æ¯æ-çæ§å¹³å°ãå¹³å°æ¥ç");
                oaBody.setBodyContent(content.toString());
                oaBody.setMsgUrl(domainUrl + "/#/app/monitorlog?taskId=" + taskVo.getId());
                msg.setoABody(oaBody);
                msg.setReceivers(Lists.newArrayList(empId));
                try {
                    McFactory.getDingMc().sendMsg(msg);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
/**
 * åééç¾¤æ¶æ¯
 * @param tokens
 * @param taskVo
 */
        public void sendDingGroupMsg (List < String > tokens, MonitorTaskVo taskVo){
            DingGroupMsgContext context = new DingGroupMsgContext(env, domainUrl, taskVo);
            for (String token : tokens) {
                try {
                    dingTalkService.sendMsg(token, context.getDingTalkMessage());
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error(e.getMessage(), e);
                }
            }
        }
/**
 * æ¯å¦è¶è¿æ¨è¿æéè®¾å®æ¶é´
 * @param taskVo
 * @return
 */
        private boolean isSendMsg (Date nowDate, MonitorTaskVo taskVo){
            boolean flag = true;
            if (taskVo.getAlertDelayTime() != null) {
                flag = nowDate.after(taskVo.getAlertDelayTime());
            }
            return flag;
        }
    }